package cn.schoolwow.quickdao.module.database.ddl.action.flow.column;

import cn.schoolwow.quickdao.annotation.IdStrategy;
import cn.schoolwow.quickdao.domain.QuickDAOConfig;
import cn.schoolwow.quickdao.domain.database.parent.DatabaseType;
import cn.schoolwow.quickdao.domain.entity.PropertyOption;
import cn.schoolwow.quickdao.domain.provider.DatabaseProvider;
import cn.schoolwow.quickdao.module.database.ddl.common.flow.GetAutoIncrementStatementCommonFlow;
import cn.schoolwow.quickdao.module.database.ddl.common.flow.GetEscapeCheckFlow;
import cn.schoolwow.quickdao.module.database.parent.flow.executor.ExecuteUpdateConnectionFlow;
import cn.schoolwow.quickflow.domain.FlowContext;
import cn.schoolwow.quickflow.flow.BusinessFlow;

public class AlterTableColumnFlow implements BusinessFlow {
    @Override
    public void executeBusinessFlow(FlowContext flowContext) throws Exception {
        checkCanAlterTableColumn(flowContext);
        flowContext.executeFlowList(new GetEscapeCheckFlow());
        setStatement(flowContext);
        executeStatement(flowContext);
    }

    @Override
    public String name() {
        return "修改表字段";
    }

    private void checkCanAlterTableColumn(FlowContext flowContext){
        DatabaseType databaseType = flowContext.checkInstanceData(DatabaseType.class);
        switch (databaseType){
            case SQLite:{
                throw new IllegalArgumentException("SQLite数据库不支持修改字段");
            }
        }
    }

    private void setStatement(FlowContext flowContext){
        DatabaseType databaseType = flowContext.checkInstanceData(DatabaseType.class);
        QuickDAOConfig quickDAOConfig = flowContext.checkInstanceData(QuickDAOConfig.class);
        String tableName = (String) flowContext.checkData("tableName");
        PropertyOption propertyOption = (PropertyOption) flowContext.checkData("propertyOption");
        String escapeCheck = (String) flowContext.getData("escapeCheck");

        DatabaseProvider databaseProvider = quickDAOConfig.databaseContext.databaseProvider;

        StringBuilder sqlBuilder = new StringBuilder("alter table " + databaseProvider.escape(tableName));
        switch (databaseType){
            case SQLServer:
            case Postgresql:{
                sqlBuilder.append(" alter");
            }break;
            default:{
                sqlBuilder.append(" modify");
            }break;
        }
        sqlBuilder.append(" column " + databaseProvider.escape(propertyOption.column));
        switch (databaseType){
            case Postgresql:{
                sqlBuilder.append(" type");
            }break;
        }
        sqlBuilder.append(" "+propertyOption.columnType);
        if(!propertyOption.columnType.contains("(")){
            sqlBuilder.append((null == propertyOption.range ? "" : "(" + propertyOption.range + ")"));
        }
        if(propertyOption.id&&propertyOption.strategy.equals(IdStrategy.AutoIncrement)){
            flowContext.startFlow(new GetAutoIncrementStatementCommonFlow())
                    .putTemporaryData("sqlBuilder", sqlBuilder)
                    .execute();
        }
        if (null!=propertyOption.notNull&&propertyOption.notNull) {
            sqlBuilder.append(" not null");
        }
        if (null != propertyOption.defaultValue && !propertyOption.defaultValue.isEmpty()) {
            sqlBuilder.append(" default " + propertyOption.defaultValue);
        }
        if (null != escapeCheck && !escapeCheck.isEmpty()) {
            sqlBuilder.append(" check " + escapeCheck);
        }
        if (null != propertyOption.comment) {
            sqlBuilder.append(" " + databaseProvider.comment(propertyOption.comment));
        }
        sqlBuilder.append(";");
        if(DatabaseType.Postgresql.equals(databaseType)){
            if(null!=propertyOption.notNull&&!propertyOption.notNull){
                sqlBuilder.append("alter table "+databaseProvider.escape(tableName)+" alter "+databaseProvider.escape(propertyOption.column)+" drop not null;");
            }
        }
        flowContext.putTemporaryData("sql", sqlBuilder.toString());
    }
    
    private void executeStatement(FlowContext flowContext){
        flowContext.startFlow(new ExecuteUpdateConnectionFlow())
                .putTemporaryData("name", "修改列")
                .execute();
    }
}
